Booleans and Conditionals
Booleans
Python有一种名为bool的变量类型。它有两个可能的值:True和False。
x = True
print(x)
print(type(x))
True
<class 'bool'>
我们通常从布尔运算符获取布尔值,而不是直接在代码中设置True或False。这些操作符回答是/否问题。我们将在下面讨论其中的一些运算符。
Comparison Operations
Operation | Description | Operation | Description | |
---|---|---|---|---|
a == b | a equal to b | a != b | a not equal to b | |
a < b | a less than b | a > b | a greater than b | |
a <= b | a less than or equal to b | a >= b | a greater than or equal to b |
def can_run_for_president(age):
"""Can someone of the given age run for president in the US?"""
# The US Constitution says you must be at least 35 years old
return age >= 35
print("Can a 19-year-old run for president?", can_run_for_president(19))
print("Can a 45-year-old run for president?", can_run_for_president(45))
Can a 19-year-old run for president? False
Can a 45-year-old run for president? True
比较通常会像你希望的那样起作用
3.0 == 3
True
但有时它们会很棘手
'3' == 3
False
比较运算符可以与我们已经看到的算术运算符相结合,以表示几乎无限范围的数学测试。例如,我们可以通过检查带2的模数是否返回1来检查一个数是否为奇数:
def is_odd(n):
return (n % 2) == 1
print("Is 100 odd?", is_odd(100))
print("Is -1 odd?", is_odd(-1))
Is 100 odd? False
Is -1 odd? True
记住在进行比较时使用==而不是=。如果你写n == 2你在问n的值,当你写n = 2你在改变n的值。
Combining Boolean Values
您可以使用“and”、“or”和“not”等标准概念组合布尔值。事实上,这样做的词是:and, or, and not。
有了这些,我们可以使can_run_for_president函数更加精确。
def can_run_for_president(age, is_natural_born_citizen):
"""Can someone of the given age and citizenship status run for president in the US?"""
# The US Constitution says you must be a natural born citizen *and* at least 35 years old
return is_natural_born_citizen and (age >= 35)
print(can_run_for_president(19, True))
print(can_run_for_president(55, False))
print(can_run_for_president(55, True))
False
False
True
快,你能猜出这个表达式的值吗?
True or True and False
True
Conditionals
当与条件语句结合使用关键字if、elif和else时,布尔值最有用。
条件语句,通常称为if-then语句,允许您根据布尔条件的值控制运行哪些代码段。这里有一个例子:
def inspect(x):
if x == 0:
print(x, "is zero")
elif x > 0:
print(x, "is positive")
elif x < 0:
print(x, "is negative")
else:
print(x, "is unlike anything I've ever seen...")
inspect(0)
inspect(-15)
0 is zero
-15 is negative
if和else关键字经常在其他语言中使用;它更独特的关键字是elif,是“else if”的缩写。在这些条件子句中,elif和else块是可选的;此外,您可以根据需要包含任意多的elif语句。
特别注意使用冒号(:)和空格来表示单独的代码块。这与我们定义函数时发生的情况类似——函数头以:结尾,下面一行缩进4个空格。所有后续的缩进行都属于函数体,直到遇到未缩进行,结束函数定义。
def f(x):
if x > 0:
print("Only printed when x is positive; x =", x)
print("Also only printed when x is positive; x =", x)
print("Always printed, regardless of x's value; x =", x)
f(1)
f(0)
Only printed when x is positive; x = 1
Also only printed when x is positive; x = 1
Always printed, regardless of x's value; x = 1
Always printed, regardless of x's value; x = 0
Boolean conversion
我们已经见过int(),它把东西变成整数,和float(),它把东西变成浮点数,所以你可能不会对Python有一个bool()函数把东西变成bool感到惊讶。
print(bool(1)) # all numbers are treated as true, except 0
print(bool(0))
print(bool("asf")) # all strings are treated as true, except the empty string ""
print(bool(""))
# Generally empty sequences (strings, lists, and other types we've yet to see like lists and tuples)
# are "falsey" and the rest are "truthy"
True
False
True
False
我们可以在if条件和其他需要布尔值的地方使用非布尔对象。Python将隐式地将它们视为对应的布尔值:
if 0:
print(0)
elif "spam":
print("spam")
spam
Exercise
Question 1
许多编程语言都将**sign(符号函数)**作为内置函数提供。Python没有,但是我们可以定义自己的!
在下面的单元格中,定义一个名为sign的函数,它接受一个数值参数,如果是负数则返回-1,如果是正数则返回1,如果是0则返回0。
# Your code goes here. Define a function called 'sign'
def sign(input):
if input > 0:
return 1
elif input == 0:
return 0
else:
return -1
# Check your answer
q1.check()
Question 2
我们决定将“logging”添加到前面练习中的to_smash函数(三个小孩分糖果的题目中提到的函数)中。
def to_smash(total_candies):
"""Return the number of leftover candies that must be smashed after distributing
the given number of candies evenly between 3 friends.
>>> to_smash(91)
1
"""
print("Splitting", total_candies, "candies")
return total_candies % 3
to_smash(91)
Splitting 91 candies
1
What happens if we call it with total_candies = 1
?
to_smash(1)
Splitting 1 candies
1
这可不是什么好语法!
修改下面单元格中的定义,以纠正print语句的语法。(如果只有一个糖果,我们应该用单数“candy”而不是复数“candies”)
def to_smash(total_candies):
"""Return the number of leftover candies that must be smashed after distributing
the given number of candies evenly between 3 friends.
>>> to_smash(91)
1
"""
if total_candies == 1:
print("Splitting", total_candies, "candy")
else:
print("Splitting", total_candies, "candies")
return total_candies % 3
to_smash(91)
to_smash(1)
Question 3
在教程中,我们讨论了我们是否为天气做好了准备。我说我不会受今天天气的影响,如果……
我有一把伞……
或者如果雨不太大,我有兜帽的话……
除此之外,我仍然很好,除非下雨,除非是工作日
下面的函数首次尝试将这个逻辑转换为Python表达式。我声称代码中有一个bug。你能找到吗?
为了证明prepared_for_weather是错误的,提出一组输入,其中:
- 函数返回False(但应该返回True),或者
- 函数返回True(但应该返回False)。
为了获得完成这个问题的积分,您的代码应该返回一个正确的结果。
def prepared_for_weather(have_umbrella, rain_level, have_hood, is_workday):
# Don't change this code. Our goal is just to find the bug, not fix it!
return have_umbrella or rain_level < 5 and have_hood or not rain_level > 0 and is_workday
# Change the values of these inputs so they represent a case where prepared_for_weather
# returns the wrong answer.
have_umbrella = False
rain_level = 0.0
have_hood = False
is_workday = False
# Check what the function returns given the current values of the variables above
actual = prepared_for_weather(have_umbrella, rain_level, have_hood, is_workday)
print(actual)
# Check your answer
q3.check()
False
Correct:
One example of a failing test case is:
have_umbrella = False
rain_level = 0.0
have_hood = False
is_workday = False
Clearly we're prepared for the weather in this case. It's not raining. Not only that, it's not a workday, so we don't even need to leave the house! But our function will return False on these inputs.
The key problem is that Python implictly parenthesizes the last part as:
(not (rain_level > 0)) and is_workday
Whereas what we were trying to express would look more like:
not (rain_level > 0 and is_workday)
Question 4
下面的函数**is_negative()**是正确实现的 —— 如果给定的数字是负数,它返回True,否则返回False。
然而,它比需要的更冗长。实际上,我们可以在保持相同行为的同时,将该函数中的代码行数减少75%。
看看你能否写出一个只使用一行代码的等价代码体,并把它放在函数concise_is_negative中。(提示:你甚至不需要Python的三元语法)
def is_negative(number):
if number < 0:
return True
else:
return False
def concise_is_negative(number):
pass # Your code goes here (try to keep it to one line!)
return True if number < 0 else False
# Check your answer
q4.check()
Question 5A
布尔变量 番茄酱、芥末和洋葱表示顾客是否想在他们的热狗上加某种配料。我们想要实现一些布尔函数,这些函数对应于一些关于客户订单的是或否问题。例如:
def wants_all_toppings(ketchup, mustard, onion):
"""Return whether the customer wants "the works" (all 3 toppings)
"""
pass
return ketchup and mustard and onion
# Check your answer
q5.a.check()
Question 5B
对于下一个函数,填写主体以匹配docstring中的英文描述。
def wants_plain_hotdog(ketchup, mustard, onion):
"""Return whether the customer wants a plain hot dog with no toppings.
"""
pass
return not ketchup and not mustard and not onion
# Check your answer
q5.b.check()
Question 5B
def exactly_one_sauce(ketchup, mustard, onion):
"""Return whether the customer wants either ketchup or mustard, but not both.
(You may be familiar with this operation under the name "exclusive or")
"""
pass
return (ketchup and not mustard) or (mustard and not ketchup)
# Check your answer
q5.c.check()
Question 6
我们已经看到,对一个整数调用bool(),如果它等于0,则返回False,否则返回True。如果在bool对象上调用int()会发生什么?在下面的笔记本单元格中尝试一下。
你能利用这一点来写一个简洁的函数来对应英语句子“顾客只需要一种配料吗?”吗?
def exactly_one_topping(ketchup, mustard, onion):
"""Return whether the customer wants exactly one of the three available toppings
on their hot dog.
"""
pass
return (ketchup + mustard + onion) == 1
# Check your answer
q6.check()
Question 7
在这个问题中,我们将使用一个简化版本的21点(又名21)。在这个版本中,有一个玩家(你)和一个发牌人。游戏流程如下:
玩家得到两张正面朝上的牌。发牌者得到一张正面朝上的牌。 玩家可以根据自己的意愿多次要求获得另一张牌(“命中”)。如果他们的牌的总和超过21,他们立即输掉这一轮。 然后发牌者给自己发更多的牌,直到: 发牌者的牌总数超过21,在这种情况下,玩家赢得这一轮 发牌者所有牌的总和大于等于17。如果玩家的总数大于发牌者,玩家获胜。否则,发牌者获胜(即使在平局的情况下)。 在计算牌的总和时,杰克、皇后和国王数为10。a可以算作1或11(当提到玩家的“总数”时,我们指的是不超过21的最大总数)。例如:A+8 = 19, A+8+8 = 17)
对于这个问题,你将编写一个表示玩家在这个游戏中的决策策略的函数。我们在下面提供了一个非常不智能的实现: